use crate::http::route;
use crate::http::server::config::Config;
use crate::http::server::handler::candidate_path::CandidatePathHandler;
use crate::http::server::handler::candidate_path_segment_list::CandidatePathSegmentListHandler;
use crate::http::server::handler::endpoint_srv6_config::EndpointSrv6ConfigHandler;
use crate::http::server::handler::network_acl::NetworkAclHandler;
use crate::http::server::handler::network_acl_rule::NetworkAclRuleHandler;
use crate::http::server::handler::node::NodeHandler;
use crate::http::server::handler::te_policy_group::TePolicyGroupHandler;
use crate::http::server::handler::traffic_steering_rule::TrafficSteeringRuleHandler;
use crate::http::server::handler::{
    AuthHandler, EndpointHandler, EndpointPeerHandler, EndpointPeerWireguardConfigHandler,
    EndpointWireguardConfigHandler,
};
use crate::http::server::middleware::AuthMiddleware;
use crate::{controller, http, mq};
use axum::Router;
use axum::routing::{get, post};
use std::sync::Arc;

pub struct Server {
    config: Config,
    handler_set: Arc<http::server::handler::HandlerSet>,
    auth_middleware: Arc<AuthMiddleware>,
}

impl Server {
    pub fn new(
        config: Config,
        controller_set: Arc<controller::ControllerSet>,
        mq_client_factory: Arc<mq::client::Factory>,
    ) -> Self {
        Self {
            config,
            handler_set: Arc::new(http::server::handler::HandlerSet::new(
                controller_set.clone(),
                mq_client_factory,
            )),
            auth_middleware: Arc::new(AuthMiddleware::new(controller_set)),
        }
    }

    pub async fn run(&self) -> Result<(), anyhow::Error> {
        let router = self.new_router();

        let listener = tokio::net::TcpListener::bind(self.config.listen_address.as_str())
            .await
            .map_err(|e| anyhow::Error::new(e))?;
        log::info!(
            "http server listening on {}",
            self.config.listen_address.as_str()
        );
        axum::serve(listener, router)
            .await
            .map_err(|e| anyhow::Error::new(e))?;
        Ok(())
    }

    fn new_router(&self) -> Router {
        let public_routes = Router::new()
            .route(route::PATH_AUTH_LOGIN_APPLY, post(AuthHandler::login_apply))
            .with_state(self.handler_set.auth.clone())
            .route(
                route::PATH_AUTH_LOGIN_SUBMIT,
                post(AuthHandler::login_submit),
            )
            .with_state(self.handler_set.auth.clone())
            .route(
                route::PATH_AUTH_REFRESH_TOKEN,
                post(AuthHandler::refresh_token),
            )
            .with_state(self.handler_set.auth.clone());

        let protected_routes = Router::new()
            // websocket
            .route(route::PATH_WS_NODES, get(NodeHandler::watch))
            .with_state(self.handler_set.node.clone())
            // endpoint
            .route(route::PATH_ENDPOINT_ADD, post(EndpointHandler::add))
            .with_state(self.handler_set.endpoint.clone())
            .route(route::PATH_ENDPOINT_LIST, post(EndpointHandler::list))
            .with_state(self.handler_set.endpoint.clone())
            .route(
                route::PATH_ENDPOINT_LIST_INFO,
                post(EndpointHandler::list_info),
            )
            .with_state(self.handler_set.endpoint.clone())
            .route(route::PATH_ENDPOINT_GET, post(EndpointHandler::get))
            .with_state(self.handler_set.endpoint.clone())
            .route(
                route::PATH_ENDPOINT_GET_INFO,
                post(EndpointHandler::get_info),
            )
            .with_state(self.handler_set.endpoint.clone())
            .route(route::PATH_ENDPOINT_UPDATE, post(EndpointHandler::update))
            .with_state(self.handler_set.endpoint.clone())
            .route(route::PATH_ENDPOINT_DELETE, post(EndpointHandler::delete))
            .with_state(self.handler_set.endpoint.clone())
            .route(route::PATH_ENDPOINT_EXISTS, post(EndpointHandler::exists))
            .with_state(self.handler_set.endpoint.clone())
            // endpoint srv6 config
            .route(
                route::PATH_ENDPOINT_SRV6_CONFIG_GET,
                post(EndpointSrv6ConfigHandler::get),
            )
            .with_state(self.handler_set.endpoint_srv6_config.clone())
            .route(
                route::PATH_ENDPOINT_SRV6_CONFIG_UPDATE,
                post(EndpointSrv6ConfigHandler::update),
            )
            .with_state(self.handler_set.endpoint_srv6_config.clone())
            // endpoint wireguard config
            .route(
                route::PATH_ENDPOINT_WIREGUARD_CONFIG_GET,
                post(EndpointWireguardConfigHandler::get),
            )
            .with_state(self.handler_set.endpoint_wireguard_config.clone())
            .route(
                route::PATH_ENDPOINT_WIREGUARD_CONFIG_UPDATE,
                post(EndpointWireguardConfigHandler::update),
            )
            .with_state(self.handler_set.endpoint_wireguard_config.clone())
            // endpoint peer
            .route(
                route::PATH_ENDPOINT_PEER_ADD,
                post(EndpointPeerHandler::add),
            )
            .with_state(self.handler_set.endpoint_peer.clone())
            .route(
                route::PATH_ENDPOINT_PEER_LIST,
                post(EndpointPeerHandler::list),
            )
            .with_state(self.handler_set.endpoint_peer.clone())
            .route(
                route::PATH_ENDPOINT_PEER_GET,
                post(EndpointPeerHandler::get),
            )
            .with_state(self.handler_set.endpoint_peer.clone())
            .route(
                route::PATH_ENDPOINT_PEER_DELETE,
                post(EndpointPeerHandler::delete),
            )
            .with_state(self.handler_set.endpoint_peer.clone())
            // endpoint peer wireguard config
            .route(
                route::PATH_ENDPOINT_PEER_WIREGUARD_CONFIG_ADD,
                post(EndpointPeerWireguardConfigHandler::add),
            )
            .with_state(self.handler_set.endpoint_peer_wireguard_config.clone())
            .route(
                route::PATH_ENDPOINT_PEER_WIREGUARD_CONFIG_GET,
                post(EndpointPeerWireguardConfigHandler::get),
            )
            .with_state(self.handler_set.endpoint_peer_wireguard_config.clone())
            .route(
                route::PATH_ENDPOINT_PEER_WIREGUARD_CONFIG_UPDATE,
                post(EndpointPeerWireguardConfigHandler::update),
            )
            .with_state(self.handler_set.endpoint_peer_wireguard_config.clone())
            // te policy group
            .route(
                route::PATH_TE_POLICY_GROUP_ADD,
                post(TePolicyGroupHandler::add),
            )
            .with_state(self.handler_set.te_policy_group.clone())
            .route(
                route::PATH_TE_POLICY_GROUP_LIST,
                post(TePolicyGroupHandler::list),
            )
            .with_state(self.handler_set.te_policy_group.clone())
            .route(
                route::PATH_TE_POLICY_GROUP_GET,
                post(TePolicyGroupHandler::get),
            )
            .with_state(self.handler_set.te_policy_group.clone())
            .route(
                route::PATH_TE_POLICY_GROUP_UPDATE,
                post(TePolicyGroupHandler::update),
            )
            .with_state(self.handler_set.te_policy_group.clone())
            .route(
                route::PATH_TE_POLICY_GROUP_DELETE,
                post(TePolicyGroupHandler::delete),
            )
            .with_state(self.handler_set.te_policy_group.clone())
            // candidate path
            .route(
                route::PATH_CANDIDATE_PATH_ADD,
                post(CandidatePathHandler::add),
            )
            .with_state(self.handler_set.candidate_path.clone())
            .route(
                route::PATH_CANDIDATE_PATH_LIST,
                post(CandidatePathHandler::list),
            )
            .with_state(self.handler_set.candidate_path.clone())
            .route(
                route::PATH_CANDIDATE_PATH_LIST_INFO,
                post(CandidatePathHandler::list_info),
            )
            .with_state(self.handler_set.candidate_path.clone())
            .route(
                route::PATH_CANDIDATE_PATH_GET,
                post(CandidatePathHandler::get),
            )
            .with_state(self.handler_set.candidate_path.clone())
            .route(
                route::PATH_CANDIDATE_PATH_GET_INFO,
                post(CandidatePathHandler::get_info),
            )
            .with_state(self.handler_set.candidate_path.clone())
            .route(
                route::PATH_CANDIDATE_PATH_UPDATE,
                post(CandidatePathHandler::update),
            )
            .with_state(self.handler_set.candidate_path.clone())
            // candidate path segment list
            .route(
                route::PATH_CANDIDATE_PATH_SEGMENT_LIST_ADD,
                post(CandidatePathSegmentListHandler::add),
            )
            .with_state(self.handler_set.candidate_path_segment_list.clone())
            .route(
                route::PATH_CANDIDATE_PATH_SEGMENT_LIST_DELETE,
                post(CandidatePathSegmentListHandler::delete),
            )
            .with_state(self.handler_set.candidate_path_segment_list.clone())
            // network acl
            .route(route::PATH_NETWORK_ACL_ADD, post(NetworkAclHandler::add))
            .with_state(self.handler_set.network_acl.clone())
            .route(route::PATH_NETWORK_ACL_LIST, post(NetworkAclHandler::list))
            .with_state(self.handler_set.network_acl.clone())
            .route(route::PATH_NETWORK_ACL_GET, post(NetworkAclHandler::get))
            .with_state(self.handler_set.network_acl.clone())
            .route(
                route::PATH_NETWORK_ACL_UPDATE,
                post(NetworkAclHandler::update),
            )
            .with_state(self.handler_set.network_acl.clone())
            .route(
                route::PATH_NETWORK_ACL_DELETE,
                post(NetworkAclHandler::delete),
            )
            .with_state(self.handler_set.network_acl.clone())
            // network acl rule
            .route(
                route::PATH_NETWORK_ACL_RULE_SET_INGRESS_RULES,
                post(NetworkAclRuleHandler::set_ingress_rules),
            )
            .with_state(self.handler_set.network_acl_rule.clone())
            .route(
                route::PATH_NETWORK_ACL_RULE_SET_EGRESS_RULES,
                post(NetworkAclRuleHandler::set_egress_rules),
            )
            .with_state(self.handler_set.network_acl_rule.clone())
            .route(
                route::PATH_NETWORK_ACL_RULE_ALL_INGRESS_RULES,
                post(NetworkAclRuleHandler::all_ingress_rules),
            )
            .with_state(self.handler_set.network_acl_rule.clone())
            .route(
                route::PATH_NETWORK_ACL_RULE_ALL_EGRESS_RULES,
                post(NetworkAclRuleHandler::all_egress_rules),
            )
            .with_state(self.handler_set.network_acl_rule.clone())
            // traffic steering rule
            .route(
                route::PATH_TRAFFIC_STEERING_RULE_ADD,
                post(TrafficSteeringRuleHandler::add),
            )
            .with_state(self.handler_set.traffic_steering_rule.clone())
            .route(
                route::PATH_TRAFFIC_STEERING_RULE_LIST,
                post(TrafficSteeringRuleHandler::list),
            )
            .with_state(self.handler_set.traffic_steering_rule.clone())
            .route(
                route::PATH_TRAFFIC_STEERING_RULE_GET,
                post(TrafficSteeringRuleHandler::get),
            )
            .with_state(self.handler_set.traffic_steering_rule.clone())
            .route(
                route::PATH_TRAFFIC_STEERING_RULE_UPDATE,
                post(TrafficSteeringRuleHandler::update),
            )
            .with_state(self.handler_set.traffic_steering_rule.clone())
            .route(
                route::PATH_TRAFFIC_STEERING_RULE_DELETE,
                post(TrafficSteeringRuleHandler::delete),
            )
            .with_state(self.handler_set.traffic_steering_rule.clone())
            .route_layer(axum::middleware::from_fn_with_state(
                self.auth_middleware.clone(),
                AuthMiddleware::auth,
            ));

        public_routes.merge(protected_routes)
    }
}
